package com.shuiyun.jdbc.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.shuiyun.jdbc.sharding.OrderPreciseShardingData;
import com.shuiyun.jdbc.sharding.OrderPreciseShardingTable;
import com.shuiyun.jdbc.sharding.OrderRangeShardingTable;
import org.apache.shardingsphere.api.config.masterslave.MasterSlaveRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.KeyGeneratorConfiguration;
import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.TableRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.strategy.InlineShardingStrategyConfiguration;
import org.apache.shardingsphere.api.config.sharding.strategy.StandardShardingStrategyConfiguration;
import org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.*;

/**
 * @author shuiyun
 */
@Configuration
public class ShardingJdbcConfig {

    /** 定义数据源 */
    Map<String, DataSource> createDataSourceMap() {
        // 这里定义了数据源
        DruidDataSource dataSource1 = new DruidDataSource();
        dataSource1.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource1.setUrl("jdbc:mysql://192.168.220.139:3306/order_db_1?useUnicode=true&characterEncoding=utf-8&useSSL=false");
        dataSource1.setUsername("root");
        dataSource1.setPassword("123456");

        DruidDataSource dataSource2 = new DruidDataSource();
        dataSource2.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource2.setUrl("jdbc:mysql://192.168.220.139:3306/order_db_2?useUnicode=true&characterEncoding=utf-8&useSSL=false");
        dataSource2.setUsername("root");
        dataSource2.setPassword("123456");

        DruidDataSource dataSource3 = new DruidDataSource();
        dataSource3.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource3.setUrl("jdbc:mysql://192.168.220.139:3306/user_db_1?useUnicode=true&characterEncoding=utf-8&useSSL=false");
        dataSource3.setUsername("root");
        dataSource3.setPassword("123456");

        DruidDataSource dataSource4 = new DruidDataSource();
        dataSource4.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource4.setUrl("jdbc:mysql://192.168.220.139:3306/user_db_2?useUnicode=true&characterEncoding=utf-8&useSSL=false");
        dataSource4.setUsername("root");
        dataSource4.setPassword("123456");

        // 这里声明了可以使用的数据源
        Map<String, DataSource> result = new HashMap<>(8);
        // 订单分表
        result.put("m1", dataSource1);
        result.put("m2", dataSource2);
        // 用户主从
        result.put("m0", dataSource3);
        result.put("s0", dataSource4);
        return result;
    }

    /** 定义主键生成策略 */
    private static KeyGeneratorConfiguration getKeyGeneratorConfiguration() {
        return new KeyGeneratorConfiguration("SNOWFLAKE","order_id");
    }

    /**  定义t_order表的分片策略 */
    TableRuleConfiguration getOrderTableRuleConfiguration() {
        TableRuleConfiguration result = new TableRuleConfiguration("t_order","m$->{1..2}.t_order_$->{1..2}");
        // 这里指定订单分表规则 根据订单ID进行分表 并且指定了精确查询和范围查询的规则
        result.setTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("order_id",new OrderPreciseShardingTable(),new OrderRangeShardingTable()));
        // 这里指定了订单表分库规则 根据用户ID进行分库 这里仅指定了精确查询规则 没有指定范围查询规则 如果需要可以参考上述订单范围查询规则
        result.setDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration("user_id",new OrderPreciseShardingData()));
        // 这里指定了逐渐生成规则，因为需要保存到不同的数据库的不同表所以需要生成唯一主键
        result.setKeyGeneratorConfig(getKeyGeneratorConfiguration());
        return result;
    }


    /** 定义t_user表的策略 可以在此读写分离的基础上 再进行分表操作 */
    TableRuleConfiguration getUserTableRuleConfiguration(){
        TableRuleConfiguration result = new TableRuleConfiguration("t_user","ds0.t_user");
        // 这里指定简单的行分即可 因为不涉及真实的分表规则
        result.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id","t_user"));
        return result;
    }

    /** 定义sharding-Jdbc数据源 */
    @Bean
    DataSource getShardingDataSource() throws SQLException {
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        // 用户表主从设置
        shardingRuleConfig.getMasterSlaveRuleConfigs().add(new MasterSlaveRuleConfiguration("ds0","m0", Collections.singletonList("s0")));
        shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration());
        shardingRuleConfig.getTableRuleConfigs().add(getUserTableRuleConfiguration());
        // 这里配置是可以打印sql
        Properties properties = new Properties();
        properties.put("sql.show","true");
        return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig,properties);
    }

}
